package net.qiqbframework.loadhanding;

import lombok.extern.slf4j.Slf4j;
import net.qiqbframework.common.utils.StringUtils;
import net.qiqbframework.config.ConfigurationException;
import net.qiqbframework.messaging.Message;
import net.qiqbframework.messaging.annotation.ExecutableHandlerWrapper;
import net.qiqbframework.messaging.annotation.MessageExecutableHandler;
import net.qiqbframework.messaging.annotation.WrappedMessageExecutableHandler;
import net.qiqbframework.modelling.domain.BizIdentifierModel;

import javax.annotation.Nonnull;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

@Slf4j
public class LoadExecutableHandlerWrapper implements ExecutableHandlerWrapper {

    @Override
    public MessageExecutableHandler wrap(@Nonnull MessageExecutableHandler original) {
        final Optional<Object> routingBizIdentifierNaming = original.attribute(LoadHandlerAnnotationAttributes.ROUTING_BIZ_ID_NAMING);
        if (routingBizIdentifierNaming.isPresent()) {
            return new LoadMessageExecutableHandlerImpl(original);
        }
        return original;
    }

    private static class LoadMessageExecutableHandlerImpl extends WrappedMessageExecutableHandler implements LoadExecutableHandler {

        private String bizIdentifierName;

        private final Class<?> bizIdentifierType;

        private Class<?> aggregateType;

        private final boolean supportBatch;


        private LoadMessageExecutableHandlerImpl(MessageExecutableHandler delegate) {
            super(delegate);
            // 获取返回值，
            final Optional<Method> originalMethodOptional = delegate.unwrap(Method.class);
            if (originalMethodOptional.isEmpty()) {

                final ConfigurationException configurationException = new ConfigurationException("The target object modified by @ LoadHandler must be a method");
                log.error("被 @LoadHandler 修饰目标对象必须是方法，但现在找不到。", configurationException);
                throw configurationException;
            }
            final Method method = originalMethodOptional.get();
            final Class<?> returnType = method.getReturnType();
            if (returnType.equals(Void.class)) {
                final ConfigurationException configurationException = new ConfigurationException("The method [%s] modified by @ LoadHandler must not be a void".formatted(method));
                log.error("被 @LoadHandler 修饰方法[{}]返回值不能是 void。", method, configurationException);
                throw configurationException;
            }
            this.bizIdentifierType = method.getParameterTypes()[0];
            supportBatch = (boolean) delegate.attribute(LoadHandlerAnnotationAttributes.SUPPORT_BATCH).orElseThrow();
            // 解析聚合根
            if (supportBatch) {
                initRoutingAggregateRootType(method);
            } else {
                this.aggregateType = method.getReturnType();
            }
            // init  bizIdentifierNaming
            final String markBizIdentifierName = (String) delegate.attribute(LoadHandlerAnnotationAttributes.ROUTING_BIZ_ID_NAMING).orElseThrow();
            if (!StringUtils.isEmptyOrNull(markBizIdentifierName)) {
                this.bizIdentifierName = markBizIdentifierName;
            }


        }

        private void initRoutingAggregateRootType(Method method) {

            // 从返回值集合泛型中获取
            Type genericReturnType = method.getGenericReturnType();

            if (genericReturnType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                // 获取实际类型参数
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

                for (Type actualTypeArgument : actualTypeArguments) {
                    this.aggregateType = (Class<?>) actualTypeArgument;
                }
            }
        }

        @Override
        public boolean canHandle(@Nonnull Message<?> message) {
            if (message instanceof LoadMessage<?> loadMessage) {
                // 判断聚合是否匹配
                if (loadMessage.getAggregateType().equals(aggregateType)) {
                    if (!StringUtils.nonEmptyOrNull(bizIdentifierName)) {
                        // 不存在，默认找类型

                        final List<BizIdentifierModel<?>> matched = loadMessage.getAggregateModel().allBizIdentifierModels().stream().filter(biz -> biz.bizIdentifierType() == bizIdentifierType).toList();
                        if (matched.isEmpty()) {
                            return false;
                        }
                        if (matched.size() == 1) {
                            bizIdentifierName = matched.get(0).modelName();
                        } else {
                            throw new IllegalArgumentException("类型[%s]找到多个业务ID".formatted(loadMessage.getPayloadType()));
                        }
                    }
                    return loadMessage.getBusinessIdName().equals(bizIdentifierName);

                }

            }
            return false;

        }

        /**
         * @param message
         * @param target
         * @return 统一转化为map
         * @throws Exception
         */
        @Override
        public Object handle(@Nonnull Message<?> message, Object target) throws Exception {
            LoadMessage<?> loadMessage = (LoadMessage<?>) message;
            // 查询
            if (loadMessage.isBatch()) {
                if (this.supportBatch) {
                    return super.handle(message, target);
                } else {
                    // 加载器不支持批量，拆分一个个的去查询
                    Map<Object, Object> resultMap = new HashMap<>();
                    for (Object id : (Collection<?>) loadMessage.getPayload()) {
                        if (resultMap.containsKey(id)) {
                            // 去掉重复
                            continue;
                        }
                        Object result = super.handle(new GenericLoadMessage<>(id, loadMessage.getBusinessIdName(), loadMessage.getAggregateModel()), target);
                        resultMap.put(id, result);
                    }
                    return resultMap;
                }
            } else {
                if (this.supportBatch) {
                    // 当前支持批量查询，但是实际没有批量查询，直接转化一个list
                    return super.handle(new BatchGenericLoadMessage<>(List.of(loadMessage.getPayload()), loadMessage.getBusinessIdName(), loadMessage.getAggregateModel()), target);
                } else {
                    final Object resultData = super.handle(loadMessage, target);
                    return Map.of(loadMessage.getPayload(), resultData);
                }

            }

        }


        @Override
        public Optional<String> bizIdentifierName() {
            return Optional.ofNullable(bizIdentifierName);
        }

        @Override
        public String aggregateName() {
            return aggregateType.getName();
        }

        @Override
        public Class<?> aggregateType() {
            return aggregateType;
        }


        @Override
        public Class<?> bizIdentifierType() {
            return bizIdentifierType;
        }

        @Override
        public void updateBizIdentifierName(String bizIdentifierName) {
            this.bizIdentifierName = bizIdentifierName;
        }


    }
}
